home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
xpat2-1.000
/
xpat2-1
/
xpat2-1.04
/
etc
/
wavplay.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-27
|
7KB
|
267 lines
/****************************************************************/
/* */
/* wavplay.c */
/* Sample .WAV player for xpat2. */
/* 1994 by M. Bischoff */
/* */
/* To use this with xpat2, do the following: */
/* 1) compile this program with */
/* $ gcc -s -O wavplay.c -o wavplay */
/* 2) Then, make a named pipe /tmp/audio: */
/* $ mknod /tmp/audio p */
/* 3) Compile the module X-sound_SUN.c with the */
/* additional option -DAUDIO_DEVICE=\"/tmp/audio\" */
/* to redirect sound output to the named pipe. */
/* 4) start the WAV-player: */
/* $ wavplay & */
/* 5) substitute all .au files with .wav files, but keep */
/* the original name. */
/* 6) start xpat2: */
/* $ xpat2 */
/* Have fun! (and don't forget to kill wavplay later) */
/* */
/****************************************************************/
#include <sys/soundcard.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
struct wavfmt {
char c_RIFF[4];
long len_file;
char c_WAVE[4];
char c_fmt[4];
long len_fmt; /* excluding c_fmt & len_fmt. 16 */
short monostereo;
short numchannels;
long samplerate;
long bytespersecond;
short bytespersample;
short bitspersample;
char c_data[4];
long len_data;
} wav_hdr;
static void stat8(unsigned char *p, int *_l, int *_u, int n) {
int l = 0, u = 0;
while (n--) {
int c;
c = ((int)*p++ - 0x80) << 8;
if (c < l)
l = c;
if (c > u)
u = c;
}
*_u = u;
*_l = l;
}
static void stat16(short *p, int *_l, int *_u, int n) {
int l = 0, u = 0;
while (n--) {
if (*p < l)
l = *p;
if (*p > u)
u = *p;
++p;
}
*_u = u;
*_l = l;
}
#if 0
static void wav_stat(void *data, const char *filename) {
int l, u;
printf("%s is %d bit %s at %ld Hz, %ld samples\n",
filename,
wav_hdr.bitspersample,
wav_hdr.monostereo != 1 ? "STEREO" : "MONO",
wav_hdr.samplerate,
wav_hdr.len_data);
if (wav_hdr.monostereo != 1)
return; /* cannot handle */
if (wav_hdr.bitspersample == 8)
stat8((unsigned char *)data, &l, &u, wav_hdr.len_data);
else if (wav_hdr.bitspersample == 16)
stat16((short *)data, &l, &u, wav_hdr.len_data / 2);
else
return;
{ double f1, f2, factor;
f1 = l < 0 ? -32768.0 / l : 65535.0;
f2 = u > 0 ? 32767.0 / u : 65535.0;
factor = f1 < f2 ? f1 : f2;
printf("min is -%04xH, max is %04xH, scale with %f for full amplitude\n", -l, u, factor);
}
}
#endif
static double abbreviation = 1.0; /* playing speed factor */
static double volumescale = 1.0; /* volume scaling factor */
static int writefile = 0;
static int fd_audio;
static void wav_play(unsigned char *data, long len, const char *filename) {
long i;
const char *fmt;
fmt = (wav_hdr.monostereo != 1) ? "STEREO" : "MONO";
if ((fd_audio=open("/dev/dsp", O_WRONLY, 0)) == EOF) {
fprintf(stderr, "Cannot open /dev/dsp");
exit(1);
}
/* speed adjust */
i = wav_hdr.samplerate;
wav_hdr.samplerate = (long)((double)wav_hdr.samplerate * abbreviation);
if (wav_hdr.samplerate > 22222) {
long j;
wav_hdr.samplerate /= 2;
len /= 2;
if (wav_hdr.bitspersample == 8)
for (j = 0; j < len; ++j)
data[j] = data[2*j];
else
for (j = 0; j < len; j += 2) {
data[j] = data[2*j];
data[j+1] = data[2*j+1];
}
}
/* volume scale */
if (wav_hdr.bitspersample == 16) {
/* 16 bit => 8 bit & scaling */
long j, clip = 0;
double new;
unsigned char *wr;
short *rd;
wr = data;
rd = (short *)data;
len /= 2;
for (j = 0; j < len; ++j) {
new = (*rd++ * volumescale) + 32768.0;
if (new < 0.0) {
new = 0.0;
++clip;
} else if (new > 65535.5) {
new = 65535.0;
++clip;
}
*wr++ = (unsigned char)(new / 256.0);
if (clip == 1) {
printf("warning: clipping at sample %ld\n", j);
++clip;
}
}
if (clip)
printf("%ld samples clipped\n", clip-1);
wav_hdr.bytespersecond >>= 1;
wav_hdr.bytespersample >>= 1;
wav_hdr.bitspersample >>= 1;
wav_hdr.len_data >>= 1;
} else if (volumescale != 1.0) {
long j, clip = 0;
double new;
printf(" *** warning: volume scaling on 8 bit data may reduce quality ***\n");
for (j = 0; j < len; ++j) {
new = ((double)data[j] - 128.0) * volumescale + 128.0;
if (new < 0.0) {
new = 0.0;
++clip;
} else if (new >= 255.5) {
++clip;
new = 255.0;
}
data[j] = (unsigned char)new;
if (clip == 1) {
printf("warning: clipping at sample %ld\n", j);
++clip;
}
}
if (clip)
printf("%ld samples clipped\n", clip-1);
}
ioctl(fd_audio, SNDCTL_DSP_SPEED, &wav_hdr.samplerate);
#if 0
printf("%8ld bytes (%s, %2d bits) %ld (%ld) Hz, file \"%s\", %d channels\n",
len, fmt, wav_hdr.bitspersample, i, wav_hdr.samplerate, filename,
wav_hdr.numchannels);
#endif
if (wav_hdr.monostereo != 1)
return; /* cannot handle */
write(fd_audio, data, len);
close(fd_audio);
if (writefile) {
FILE *fp;
fp = fopen("/tmp/audio.wav", "wb");
fwrite(&wav_hdr, 1, sizeof(struct wavfmt), fp);
fwrite(data, 1, wav_hdr.len_data, fp);
fclose(fp);
}
}
static void *readfile(const char *filename) {
int fd;
size_t cnt;
void *data;
if ((fd = open(filename, O_RDONLY)) < 0) {
fprintf(stderr, "failed to open %s\n", filename);
return NULL;
}
if ((cnt = read(fd, &wav_hdr, sizeof(wav_hdr))) != sizeof(wav_hdr)) {
fprintf(stderr, "failed to read %s: only got %d byte\n", filename, cnt);
close(fd);
return NULL;
}
#if 0
fprintf(stderr, "audio data length is %d byte\n", wav_hdr.len_data);
fprintf(stderr, "first bytes are %c%c%c%c \n",
wav_hdr.c_RIFF[0], wav_hdr.c_RIFF[1],
wav_hdr.c_RIFF[2], wav_hdr.c_RIFF[3]);
#endif
if (!(data = malloc(wav_hdr.len_data))) {
fprintf(stderr, "not enough memory to read %s\n", filename);
close(fd);
return NULL;
}
/* read the data. This may loop */
{ int rest, this;
char *ptr;
rest = wav_hdr.len_data;
ptr = data;
while (rest && (this = read(fd, ptr, rest))) {
ptr += this;
rest -= this;
}
if (rest) {
fprintf(stderr, "cannot read chunk, %s\n", filename);
close(fd);
free(data);
return NULL;
}
}
close(fd);
return data;
}
int main(int argc, char *argv[]) {
for (;;) {
void *data;
if (!(data = readfile("/tmp/audio")))
continue;
wav_play(data, wav_hdr.len_data, "/tmp/audio");
free(data);
}
return 0;
}